package org.carl.base.dingtalk.bot.aspectj;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.text.StrFormatter;
import cn.hutool.core.util.StrUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.carl.base.dingtalk.bot.annotation.DingTalkNotify;
import org.carl.base.dingtalk.bot.model.DingTalkResult;
import org.carl.base.dingtalk.bot.model.TextMsgModel;
import org.carl.base.dingtalk.bot.service.DingTalkService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 操作日志记录处理
 *
 * @author Administrator
 */
@Aspect
public class DingTalkNotifyAspect {
    private static final Logger LOG = Logger.getGlobal();
    @Autowired
    private DingTalkService feiShuBotService;
    /**
     * 表达式缓存
     */
    private static final Map<Integer, Expression> EXPRESSION_CAHCE = new ConcurrentHashMap<>();

    /**
     * 处理完请求后执行
     *
     * @param joinPoint 切点
     */
    @AfterReturning(pointcut = "@annotation(notify)")
    public void doAfterReturning(JoinPoint joinPoint, DingTalkNotify notify) {
        handleNotify(joinPoint, notify, null);
    }


    protected void handleNotify(final JoinPoint joinPoint, DingTalkNotify notify, final Exception e) {
        try {
            // 下面两个数组中，参数值和参数名的个数和位置是一一对应的。
            // 参数值
            Object[] args = joinPoint.getArgs();
            // 参数名
            String[] argNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames();

            EvaluationContext context = new StandardEvaluationContext();
            for (int i = 0; i < args.length; i++) {
                context.setVariable(argNames[i], args[i]);
                context.setVariable(("p" + i), args[i]);
            }
            boolean isContinue = true;
            if (StrUtil.isNotBlank(notify.condition())) {
                Object condition = getExpression(notify.condition()).getValue(context);
                isContinue = Convert.toBool(condition, false);
            }
            if (!isContinue) {
                //如果表达式为false,则不再执行
                LOG.log(Level.INFO, "发送钉钉通知条件:" + notify.condition() + "不满足,不予执行.");
                return;
            }
            if (StrUtil.isBlank(notify.template())) {
                return;
            }
            TextMsgModel textMsgModel = null;
            //如果参数列表为空则不需要解析参数
            if (notify.args() != null && notify.args().length > 0) {
                String[] notifyArgs = notify.args();
                String[] notifyParams = new String[notifyArgs.length];
                for (int i = 0; i < notifyArgs.length; i++) {
                    String param = getExpression(notifyArgs[i]).getValue(context, String.class);
                    notifyParams[i] = param;
                }
                textMsgModel = TextMsgModel.text(StrFormatter.format(notify.template(), notifyParams));
            } else {
                textMsgModel = TextMsgModel.text(StrFormatter.format(notify.template()));
            }
            DingTalkResult shuBotRespResult = feiShuBotService.sendBot(notify.botId(), textMsgModel);
            LOG.log(Level.INFO, "钉钉通知发送结果:" + shuBotRespResult.toString());
        } catch (Exception exp) {
            LOG.log(Level.WARNING, "钉钉通知发送失败:" + exp.getMessage(), exp);
        }
    }

    /**
     * 根据公式字符串获取编译公式
     *
     * @param expression
     * @return
     */
    public static Expression getExpression(String expression) {
        if (EXPRESSION_CAHCE.containsKey(expression.hashCode())) {
            return EXPRESSION_CAHCE.get(expression.hashCode());
        }
        ExpressionParser parser = new SpelExpressionParser();
        Expression parseExpression = parser.parseExpression(expression);
        EXPRESSION_CAHCE.put(expression.hashCode(), parseExpression);
        return parseExpression;
    }
}
